Debug mode for string. This commit also marks the first time libc++ debug-mode has found a bug (found one in regex). Had to play with extern templates a bit to get this to work since string is heavily used within libc++.dylib. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@189114 91177308-0d34-0410-b5e6-96231b3b80d8 
diff --git a/include/string b/include/string index 7439b56..761ff52 100644 --- a/include/string +++ b/include/string 
@@ -447,7 +447,7 @@  #ifndef _LIBCPP_HAS_NO_UNICODE_CHARS  #include <cstdint>  #endif -#if defined(_LIBCPP_NO_EXCEPTIONS) || defined(_LIBCPP_DEBUG) +#if defined(_LIBCPP_NO_EXCEPTIONS)  #include <cassert>  #endif   @@ -605,6 +605,7 @@  _CharT*  char_traits<_CharT>::copy(char_type* __s1, const char_type* __s2, size_t __n)  { + _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");  char_type* __r = __s1;  for (; __n; --__n, ++__s1, ++__s2)  assign(*__s1, *__s2); @@ -656,7 +657,10 @@  {return (char_type*)memmove(__s1, __s2, __n);}  _LIBCPP_INLINE_VISIBILITY  static char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) - {return (char_type*)memcpy(__s1, __s2, __n);} + { + _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range"); + return (char_type*)memcpy(__s1, __s2, __n); + }  _LIBCPP_INLINE_VISIBILITY  static char_type* assign(char_type* __s, size_t __n, char_type __a)  {return (char_type*)memset(__s, to_int_type(__a), __n);} @@ -713,7 +717,10 @@  {return (char_type*)wmemmove(__s1, __s2, __n);}  _LIBCPP_INLINE_VISIBILITY  static char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) - {return (char_type*)wmemcpy(__s1, __s2, __n);} + { + _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range"); + return (char_type*)wmemcpy(__s1, __s2, __n); + }  _LIBCPP_INLINE_VISIBILITY  static char_type* assign(char_type* __s, size_t __n, char_type __a)  {return (char_type*)wmemset(__s, __a, __n);} @@ -841,6 +848,7 @@  char16_t*  char_traits<char16_t>::copy(char_type* __s1, const char_type* __s2, size_t __n)  { + _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");  char_type* __r = __s1;  for (; __n; --__n, ++__s1, ++__s2)  assign(*__s1, *__s2); @@ -961,6 +969,7 @@  char32_t*  char_traits<char32_t>::copy(char_type* __s1, const char_type* __s2, size_t __n)  { + _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");  char_type* __r = __s1;  for (; __n; --__n, ++__s1, ++__s2)  assign(*__s1, *__s2); @@ -1072,13 +1081,13 @@  typedef const value_type& const_reference;  typedef typename __alloc_traits::pointer pointer;  typedef typename __alloc_traits::const_pointer const_pointer; -#ifdef _LIBCPP_DEBUG - typedef __debug_iter<basic_string, pointer> iterator; - typedef __debug_iter<basic_string, const_pointer> const_iterator;   - friend class __debug_iter<basic_string, pointer>; - friend class __debug_iter<basic_string, const_pointer>; -#elif defined(_LIBCPP_RAW_ITERATORS) + static_assert(is_pod<value_type>::value, "Character type of basic_string must be a POD"); + static_assert((is_same<_CharT, value_type>::value), + "traits_type::char_type must be the same type as CharT"); + static_assert((is_same<typename allocator_type::value_type, value_type>::value), + "Allocator::value_type must be same type as value_type"); +#if defined(_LIBCPP_RAW_ITERATORS)  typedef pointer iterator;  typedef const_pointer const_iterator;  #else // defined(_LIBCPP_RAW_ITERATORS) @@ -1152,9 +1161,9 @@    #endif // _LIBCPP_ALTERNATE_STRING_LAYOUT   - union __lx{__long __lx; __short __lxx;}; + union __ulx{__long __lx; __short __lxx;};   - enum {__n_words = sizeof(__lx) / sizeof(size_type)}; + enum {__n_words = sizeof(__ulx) / sizeof(size_type)};    struct __raw  { @@ -1173,15 +1182,6 @@    __compressed_pair<__rep, allocator_type> __r_;   -#ifdef _LIBCPP_DEBUG - - pair<iterator*, const_iterator*> __iterator_list_; - - _LIBCPP_INLINE_VISIBILITY iterator*& __get_iterator_list(iterator*) {return __iterator_list_.first;} - _LIBCPP_INLINE_VISIBILITY const_iterator*& __get_iterator_list(const_iterator*) {return __iterator_list_.second;} - -#endif // _LIBCPP_DEBUG -  public:  static const size_type npos = -1;   @@ -1239,7 +1239,20 @@  basic_string& operator=(initializer_list<value_type> __il) {return assign(__il.begin(), __il.size());}  #endif // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS   -#ifndef _LIBCPP_DEBUG +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_INLINE_VISIBILITY + iterator begin() _NOEXCEPT + {return iterator(this, __get_pointer());} + _LIBCPP_INLINE_VISIBILITY + const_iterator begin() const _NOEXCEPT + {return const_iterator(this, __get_pointer());} + _LIBCPP_INLINE_VISIBILITY + iterator end() _NOEXCEPT + {return iterator(this, __get_pointer() + size());} + _LIBCPP_INLINE_VISIBILITY + const_iterator end() const _NOEXCEPT + {return const_iterator(this, __get_pointer() + size());} +#else  _LIBCPP_INLINE_VISIBILITY  iterator begin() _NOEXCEPT  {return iterator(__get_pointer());} @@ -1252,12 +1265,7 @@  _LIBCPP_INLINE_VISIBILITY  const_iterator end() const _NOEXCEPT  {return const_iterator(__get_pointer() + size());} -#else // _LIBCPP_DEBUG - _LIBCPP_INLINE_VISIBILITY iterator begin() {return iterator(this, __get_pointer());} - _LIBCPP_INLINE_VISIBILITY const_iterator begin() const {return const_iterator(this, data());} - _LIBCPP_INLINE_VISIBILITY iterator end() {return iterator(this, __get_pointer() + size());} - _LIBCPP_INLINE_VISIBILITY const_iterator end() const {return const_iterator(this, data() + size());} -#endif // _LIBCPP_DEBUG +#endif // _LIBCPP_DEBUG_LEVEL >= 2  _LIBCPP_INLINE_VISIBILITY  reverse_iterator rbegin() _NOEXCEPT  {return reverse_iterator(end());} @@ -1520,6 +1528,15 @@  bool __is_long() const _NOEXCEPT  {return bool(__r_.first().__s.__size_ & __short_mask);}   +#if _LIBCPP_DEBUG_LEVEL >= 2 + + bool __dereferenceable(const const_iterator* __i) const; + bool __decrementable(const const_iterator* __i) const; + bool __addable(const const_iterator* __i, ptrdiff_t __n) const; + bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const; + +#endif // _LIBCPP_DEBUG_LEVEL >= 2 +  private:  _LIBCPP_INLINE_VISIBILITY  allocator_type& __alloc() _NOEXCEPT @@ -1732,60 +1749,43 @@  };    template <class _CharT, class _Traits, class _Allocator> -#ifndef _LIBCPP_DEBUG  _LIBCPP_INLINE_VISIBILITY inline -#endif  void  basic_string<_CharT, _Traits, _Allocator>::__invalidate_all_iterators()  { -#ifdef _LIBCPP_DEBUG - iterator::__remove_all(this); - const_iterator::__remove_all(this); -#endif // _LIBCPP_DEBUG +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__invalidate_all(this); +#endif // _LIBCPP_DEBUG_LEVEL >= 2  }    template <class _CharT, class _Traits, class _Allocator> -#ifndef _LIBCPP_DEBUG  _LIBCPP_INLINE_VISIBILITY inline -#endif  void  basic_string<_CharT, _Traits, _Allocator>::__invalidate_iterators_past(size_type -#ifdef _LIBCPP_DEBUG +#if _LIBCPP_DEBUG_LEVEL >= 2  __pos  #endif  )  { -#ifdef _LIBCPP_DEBUG - const_iterator __beg = begin(); - if (__iterator_list_.first) +#if _LIBCPP_DEBUG_LEVEL >= 2 + __c_node* __c = __get_db()->__find_c_and_lock(this); + if (__c)  { - for (iterator* __p = __iterator_list_.first; __p;) + const_pointer __new_last = __get_pointer() + __pos; + for (__i_node** __p = __c->end_; __p != __c->beg_; )  { - if (*__p - __beg > static_cast<difference_type>(__pos)) + --__p; + const_iterator* __i = static_cast<const_iterator*>((*__p)->__i_); + if (__i->base() > __new_last)  { - iterator* __n = __p; - __p = __p->__next; - __n->__remove_owner(); + (*__p)->__c_ = nullptr; + if (--__c->end_ != __p) + memmove(__p, __p+1, (__c->end_ - __p)*sizeof(__i_node*));  } - else - __p = __p->__next;  } + __get_db()->unlock();  } - if (__iterator_list_.second) - { - for (const_iterator* __p = __iterator_list_.second; __p;) - { - if (*__p - __beg > static_cast<difference_type>(__pos)) - { - const_iterator* __n = __p; - __p = __p->__next; - __n->__remove_owner(); - } - else - __p = __p->__next; - } - } -#endif // _LIBCPP_DEBUG +#endif // _LIBCPP_DEBUG_LEVEL >= 2  }    template <class _CharT, class _Traits, class _Allocator> @@ -1793,6 +1793,9 @@  basic_string<_CharT, _Traits, _Allocator>::basic_string()  _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __zero();  }   @@ -1801,6 +1804,9 @@  basic_string<_CharT, _Traits, _Allocator>::basic_string(const allocator_type& __a)  : __r_(__a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __zero();  }   @@ -1856,10 +1862,11 @@  _LIBCPP_INLINE_VISIBILITY inline  basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "basic_string(const char*) detected nullptr");  __init(__s, traits_type::length(__s)); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _CharT, class _Traits, class _Allocator> @@ -1867,20 +1874,22 @@  basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, const allocator_type& __a)  : __r_(__a)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "basic_string(const char*, allocator) detected nullptr");  __init(__s, traits_type::length(__s)); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _CharT, class _Traits, class _Allocator>  _LIBCPP_INLINE_VISIBILITY inline  basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, size_type __n)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "basic_string(const char*, n) detected nullptr");  __init(__s, __n); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _CharT, class _Traits, class _Allocator> @@ -1888,10 +1897,11 @@  basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, size_type __n, const allocator_type& __a)  : __r_(__a)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "basic_string(const char*, n, allocator) detected nullptr");  __init(__s, __n); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _CharT, class _Traits, class _Allocator> @@ -1902,6 +1912,9 @@  __r_.first().__r = __str.__r_.first().__r;  else  __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size()); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _CharT, class _Traits, class _Allocator> @@ -1912,6 +1925,9 @@  __r_.first().__r = __str.__r_.first().__r;  else  __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size()); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES @@ -1923,8 +1939,10 @@  : __r_(_VSTD::move(__str.__r_))  {  __str.__zero(); -#ifdef _LIBCPP_DEBUG - __str.__invalidate_all_iterators(); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); + if (__is_long()) + __get_db()->swap(this, &__str);  #endif  }   @@ -1938,8 +1956,10 @@  else  __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());  __str.__zero(); -#ifdef _LIBCPP_DEBUG - __str.__invalidate_all_iterators(); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); + if (__is_long()) + __get_db()->swap(this, &__str);  #endif  }   @@ -1974,6 +1994,9 @@  basic_string<_CharT, _Traits, _Allocator>::basic_string(size_type __n, value_type __c)  {  __init(__n, __c); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _CharT, class _Traits, class _Allocator> @@ -1982,6 +2005,9 @@  : __r_(__a)  {  __init(__n, __c); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _CharT, class _Traits, class _Allocator> @@ -1993,6 +2019,9 @@  if (__pos > __str_sz)  this->__throw_out_of_range();  __init(__str.data() + __pos, _VSTD::min(__n, __str_sz - __pos)); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _CharT, class _Traits, class _Allocator> @@ -2060,6 +2089,9 @@  basic_string<_CharT, _Traits, _Allocator>::basic_string(_InputIterator __first, _InputIterator __last)  {  __init(__first, __last); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _CharT, class _Traits, class _Allocator> @@ -2070,6 +2102,9 @@  : __r_(__a)  {  __init(__first, __last); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    #ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS @@ -2079,6 +2114,9 @@  basic_string<_CharT, _Traits, _Allocator>::basic_string(initializer_list<value_type> __il)  {  __init(__il.begin(), __il.end()); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _CharT, class _Traits, class _Allocator> @@ -2087,6 +2125,9 @@  : __r_(__a)  {  __init(__il.begin(), __il.end()); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    #endif // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS @@ -2094,7 +2135,9 @@  template <class _CharT, class _Traits, class _Allocator>  basic_string<_CharT, _Traits, _Allocator>::~basic_string()  { - __invalidate_all_iterators(); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__erase_c(this); +#endif  if (__is_long())  __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap());  } @@ -2166,9 +2209,7 @@  basic_string<_CharT, _Traits, _Allocator>&  basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s, size_type __n)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::assign recieved nullptr");  size_type __cap = capacity();  if (__cap >= __n)  { @@ -2342,9 +2383,7 @@  basic_string<_CharT, _Traits, _Allocator>&  basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::assign recieved nullptr");  return assign(__s, traits_type::length(__s));  }   @@ -2354,9 +2393,7 @@  basic_string<_CharT, _Traits, _Allocator>&  basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_type __n)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::append recieved nullptr");  size_type __cap = capacity();  size_type __sz = size();  if (__cap - __sz >= __n) @@ -2493,9 +2530,7 @@  basic_string<_CharT, _Traits, _Allocator>&  basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::append recieved nullptr");  return append(__s, traits_type::length(__s));  }   @@ -2505,9 +2540,7 @@  basic_string<_CharT, _Traits, _Allocator>&  basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s, size_type __n)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::insert recieved nullptr");  size_type __sz = size();  if (__pos > __sz)  this->__throw_out_of_range(); @@ -2576,13 +2609,22 @@  >::type  basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _InputIterator __first, _InputIterator __last)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this, + "string::insert(iterator, range) called with an iterator not" + " referring to this string"); +#endif  size_type __old_sz = size();  difference_type __ip = __pos - begin();  for (; __first != __last; ++__first)  push_back(*__first);  pointer __p = __get_pointer();  _VSTD::rotate(__p + __ip, __p + __old_sz, __p + size()); +#if _LIBCPP_DEBUG_LEVEL >= 2 + return iterator(this, __p + __ip); +#else  return iterator(__p + __ip); +#endif  }    template <class _CharT, class _Traits, class _Allocator> @@ -2594,6 +2636,11 @@  >::type  basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _ForwardIterator __first, _ForwardIterator __last)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this, + "string::insert(iterator, range) called with an iterator not" + " referring to this string"); +#endif  size_type __ip = static_cast<size_type>(__pos - begin());  size_type __sz = size();  size_type __cap = capacity(); @@ -2645,9 +2692,7 @@  basic_string<_CharT, _Traits, _Allocator>&  basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::insert recieved nullptr");  return insert(__pos, __s, traits_type::length(__s));  }   @@ -2682,6 +2727,11 @@  typename basic_string<_CharT, _Traits, _Allocator>::iterator  basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, size_type __n, value_type __c)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this, + "string::insert(iterator, n, value) called with an iterator not" + " referring to this string"); +#endif  difference_type __p = __pos - begin();  insert(static_cast<size_type>(__p), __n, __c);  return begin() + __p; @@ -2693,9 +2743,7 @@  basic_string<_CharT, _Traits, _Allocator>&  basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s, size_type __n2)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n2 == 0 || __s != nullptr, "string::replace recieved nullptr");  size_type __sz = size();  if (__pos > __sz)  this->__throw_out_of_range(); @@ -2827,9 +2875,7 @@  basic_string<_CharT, _Traits, _Allocator>&  basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s)  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::replace recieved nullptr");  return replace(__pos, __n1, __s, traits_type::length(__s));  }   @@ -2895,6 +2941,13 @@  typename basic_string<_CharT, _Traits, _Allocator>::iterator  basic_string<_CharT, _Traits, _Allocator>::erase(const_iterator __pos)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this, + "string::erase(iterator) called with an iterator not" + " referring to this string"); +#endif + _LIBCPP_ASSERT(__pos != end(), + "string::erase(iterator) called with a non-dereferenceable iterator");  iterator __b = begin();  size_type __r = static_cast<size_type>(__pos - __b);  erase(__r, 1); @@ -2906,6 +2959,12 @@  typename basic_string<_CharT, _Traits, _Allocator>::iterator  basic_string<_CharT, _Traits, _Allocator>::erase(const_iterator __first, const_iterator __last)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__first) == this, + "string::erase(iterator, iterator) called with an iterator not" + " referring to this string"); +#endif + _LIBCPP_ASSERT(__first <= __last, "string::erase(first, last) called with invalid range");  iterator __b = begin();  size_type __r = static_cast<size_type>(__first - __b);  erase(__r, static_cast<size_type>(__last - __first)); @@ -2917,9 +2976,7 @@  void  basic_string<_CharT, _Traits, _Allocator>::pop_back()  { -#ifdef _LIBCPP_DEBUG - assert(!empty()); -#endif + _LIBCPP_ASSERT(!empty(), "string::pop_back(): string is already empty");  size_type __sz;  if (__is_long())  { @@ -3064,9 +3121,7 @@  typename basic_string<_CharT, _Traits, _Allocator>::const_reference  basic_string<_CharT, _Traits, _Allocator>::operator[](size_type __pos) const  { -#ifdef __LIBCPP_DEBUG - assert(__pos <= size()); -#endif + _LIBCPP_ASSERT(__pos <= size(), "string index out of bounds");  return *(data() + __pos);  }   @@ -3075,9 +3130,7 @@  typename basic_string<_CharT, _Traits, _Allocator>::reference  basic_string<_CharT, _Traits, _Allocator>::operator[](size_type __pos)  { -#ifdef __LIBCPP_DEBUG - assert(__pos < size()); -#endif + _LIBCPP_ASSERT(__pos <= size(), "string index out of bounds");  return *(__get_pointer() + __pos);  }   @@ -3104,9 +3157,7 @@  typename basic_string<_CharT, _Traits, _Allocator>::reference  basic_string<_CharT, _Traits, _Allocator>::front()  { -#ifdef _LIBCPP_DEBUG - assert(!empty()); -#endif + _LIBCPP_ASSERT(!empty(), "string::front(): string is empty");  return *__get_pointer();  }   @@ -3115,9 +3166,7 @@  typename basic_string<_CharT, _Traits, _Allocator>::const_reference  basic_string<_CharT, _Traits, _Allocator>::front() const  { -#ifdef _LIBCPP_DEBUG - assert(!empty()); -#endif + _LIBCPP_ASSERT(!empty(), "string::front(): string is empty");  return *data();  }   @@ -3126,9 +3175,7 @@  typename basic_string<_CharT, _Traits, _Allocator>::reference  basic_string<_CharT, _Traits, _Allocator>::back()  { -#ifdef _LIBCPP_DEBUG - assert(!empty()); -#endif + _LIBCPP_ASSERT(!empty(), "string::back(): string is empty");  return *(__get_pointer() + size() - 1);  }   @@ -3137,9 +3184,7 @@  typename basic_string<_CharT, _Traits, _Allocator>::const_reference  basic_string<_CharT, _Traits, _Allocator>::back() const  { -#ifdef _LIBCPP_DEBUG - assert(!empty()); -#endif + _LIBCPP_ASSERT(!empty(), "string::back(): string is empty");  return *(data() + size() - 1);  }   @@ -3170,12 +3215,15 @@  _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||  __is_nothrow_swappable<allocator_type>::value)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + if (!__is_long()) + __get_db()->__invalidate_all(this); + if (!__str.__is_long()) + __get_db()->__invalidate_all(&__str); + __get_db()->swap(this, &__str); +#endif  _VSTD::swap(__r_.first(), __str.__r_.first());  __swap_alloc(__alloc(), __str.__alloc()); -#ifdef _LIBCPP_DEBUG - __invalidate_all_iterators(); - __str.__invalidate_all_iterators(); -#endif // _LIBCPP_DEBUG  }    // find @@ -3195,9 +3243,7 @@  size_type __pos,  size_type __n) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find(): recieved nullptr");  size_type __sz = size();  if (__pos > __sz || __sz - __pos < __n)  return npos; @@ -3226,9 +3272,7 @@  basic_string<_CharT, _Traits, _Allocator>::find(const value_type* __s,  size_type __pos) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::find(): recieved nullptr");  return find(__s, __pos, traits_type::length(__s));  }   @@ -3255,9 +3299,7 @@  size_type __pos,  size_type __n) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::rfind(): recieved nullptr");  size_type __sz = size();  __pos = _VSTD::min(__pos, __sz);  if (__n < __sz - __pos) @@ -3287,9 +3329,7 @@  basic_string<_CharT, _Traits, _Allocator>::rfind(const value_type* __s,  size_type __pos) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::rfind(): recieved nullptr");  return rfind(__s, __pos, traits_type::length(__s));  }   @@ -3323,9 +3363,7 @@  size_type __pos,  size_type __n) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_first_of(): recieved nullptr");  size_type __sz = size();  if (__pos >= __sz || __n == 0)  return npos; @@ -3352,9 +3390,7 @@  basic_string<_CharT, _Traits, _Allocator>::find_first_of(const value_type* __s,  size_type __pos) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::find_first_of(): recieved nullptr");  return find_first_of(__s, __pos, traits_type::length(__s));  }   @@ -3375,9 +3411,7 @@  size_type __pos,  size_type __n) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_last_of(): recieved nullptr");  if (__n != 0)  {  size_type __sz = size(); @@ -3411,9 +3445,7 @@  basic_string<_CharT, _Traits, _Allocator>::find_last_of(const value_type* __s,  size_type __pos) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::find_last_of(): recieved nullptr");  return find_last_of(__s, __pos, traits_type::length(__s));  }   @@ -3434,9 +3466,7 @@  size_type __pos,  size_type __n) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_first_not_of(): recieved nullptr");  size_type __sz = size();  if (__pos < __sz)  { @@ -3464,9 +3494,7 @@  basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const value_type* __s,  size_type __pos) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::find_first_not_of(): recieved nullptr");  return find_first_not_of(__s, __pos, traits_type::length(__s));  }   @@ -3496,9 +3524,7 @@  size_type __pos,  size_type __n) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_last_not_of(): recieved nullptr");  size_type __sz = size();  if (__pos < __sz)  ++__pos; @@ -3526,9 +3552,7 @@  basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const value_type* __s,  size_type __pos) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::find_last_not_of(): recieved nullptr");  return find_last_not_of(__s, __pos, traits_type::length(__s));  }   @@ -3599,9 +3623,7 @@  int  basic_string<_CharT, _Traits, _Allocator>::compare(const value_type* __s) const _NOEXCEPT  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::compare(): recieved nullptr");  return compare(0, npos, __s, traits_type::length(__s));  }   @@ -3611,9 +3633,7 @@  size_type __n1,  const value_type* __s) const  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__s != nullptr, "string::compare(): recieved nullptr");  return compare(__pos1, __n1, __s, traits_type::length(__s));  }   @@ -3624,9 +3644,7 @@  const value_type* __s,  size_type __n2) const  { -#ifdef _LIBCPP_DEBUG - assert(__s != 0); -#endif + _LIBCPP_ASSERT(__n2 == 0 || __s != nullptr, "string::compare(): recieved nullptr");  size_type __sz = size();  if (__pos1 > __sz || __n2 == npos)  this->__throw_out_of_range(); @@ -4102,6 +4120,42 @@    #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES   +#if _LIBCPP_DEBUG_LEVEL >= 2 + +template<class _CharT, class _Traits, class _Allocator> +bool +basic_string<_CharT, _Traits, _Allocator>::__dereferenceable(const const_iterator* __i) const +{ + return this->data() <= _VSTD::__to_raw_pointer(__i->base()) && + _VSTD::__to_raw_pointer(__i->base()) < this->data() + this->size(); +} + +template<class _CharT, class _Traits, class _Allocator> +bool +basic_string<_CharT, _Traits, _Allocator>::__decrementable(const const_iterator* __i) const +{ + return this->data() < _VSTD::__to_raw_pointer(__i->base()) && + _VSTD::__to_raw_pointer(__i->base()) <= this->data() + this->size(); +} + +template<class _CharT, class _Traits, class _Allocator> +bool +basic_string<_CharT, _Traits, _Allocator>::__addable(const const_iterator* __i, ptrdiff_t __n) const +{ + const value_type* __p = _VSTD::__to_raw_pointer(__i->base()) + __n; + return this->data() <= __p && __p <= this->data() + this->size(); +} + +template<class _CharT, class _Traits, class _Allocator> +bool +basic_string<_CharT, _Traits, _Allocator>::__subscriptable(const const_iterator* __i, ptrdiff_t __n) const +{ + const value_type* __p = _VSTD::__to_raw_pointer(__i->base()) + __n; + return this->data() <= __p && __p < this->data() + this->size(); +} + +#endif // _LIBCPP_DEBUG_LEVEL >= 2 +  #if _LIBCPP_STD_VER > 11   // Literal suffixes for basic_string [basic.string.literals]  // inline // Deviation from N3690. @@ -4140,10 +4194,7 @@    _LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS basic_string<char>)  _LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS basic_string<wchar_t>) - -extern template - string - operator+<char, char_traits<char>, allocator<char> >(char const*, string const&); +_LIBCPP_EXTERN_TEMPLATE(string operator+<char, char_traits<char>, allocator<char> >(char const*, string const&))    _LIBCPP_END_NAMESPACE_STD